package config

import (
	"gopkg.in/yaml.v3"
	"os"
	"time"

	_err "github.com/romapres2010/goapp/pkg/common/error"
	_httplog "github.com/romapres2010/goapp/pkg/common/httplog"
	_httpserver "github.com/romapres2010/goapp/pkg/common/httpserver"
	_http "github.com/romapres2010/goapp/pkg/common/httpservice"
	_log "github.com/romapres2010/goapp/pkg/common/logger"
	_metrics "github.com/romapres2010/goapp/pkg/common/metrics"
	_wpservice "github.com/romapres2010/goapp/pkg/common/workerpoolservice"

	httphandler "github.com/romapres2010/goapp/pkg/app/httphandler"
)

const (
	ENV_APP_CONFIG_FILE      = "APP_CONFIG_FILE"
	ENV_APP_HTTP_LISTEN_SPEC = "APP_HTTP_LISTEN_SPEC"
	ENV_APP_HTTP_USER        = "APP_HTTP_USER"
	ENV_APP_HTTP_PASS        = "APP_HTTP_PASS"
	ENV_APP_LOG_LEVEL        = "APP_LOG_LEVEL"
	ENV_APP_LOG_FILE         = "APP_LOG_FILE"
	ENV_APP_JWT_KEY          = "APP_JWT_KEY"
	ENV_APP_PG_HOST          = "APP_PG_HOST"
	ENV_APP_PG_PORT          = "APP_PG_PORT"
	ENV_APP_PG_DBNAME        = "APP_PG_DBNAME"
	ENV_APP_PG_USER          = "APP_PG_USER"
	ENV_APP_PG_PASS          = "APP_PG_PASS"
)

// Config represent daemon options
type Config struct {
	MemoryLimit     int64         // 推荐的内存限制（字节）- 用于在容器中启动
	ConfigFile      string        // 主要的配置文件
	ShutdownTimeout time.Duration // 强制关闭守护进程的最大时间

	ArgsConfigFile     string // 主要的配置文件
	ArgsHTTPListenSpec string // 命令行中的HTTP监听字符串
	ArgsHTTPUser       string // 命令行中用于HTTP基础认证的用户
	ArgsHTTPPass       string // 命令行中用于HTTP基础认证的密码
	ArgsJwtKey         string // 命令行中的JWT密钥
	ArgsLogLevel       string // 命令行中的日志级别
	ArgsLogFile        string // 日志文件的位置
	ArgsPgHost         string // 数据库主机
	ArgsPgPort         string // 数据库端口
	ArgsPgDBName       string // 数据库名称
	ArgsPgUser         string // 数据库用户
	ArgsPgPass         string // 数据库用户的密码

	EnvConfigFile     string // 主要的配置文件
	EnvHTTPListenSpec string // 命令行中的HTTP监听字符串
	EnvHTTPUser       string // 命令行中用于HTTP基础认证的用户
	EnvHTTPPass       string // 命令行中用于HTTP基础认证的密码
	EnvJwtKey         string // 命令行中的JWT密钥
	EnvLogLevel       string // 命令行中的日志级别
	EnvLogFile        string // 日志文件的位置
	EnvPgHost         string // 数据库主机
	EnvPgPort         string // 数据库端口
	EnvPgDBName       string // 数据库名称
	EnvPgUser         string // 数据库用户
	EnvPgPass         string // 数据库用户的密码

	// 嵌套服务的配置
	LoggerCfg            _log.Config        // 日志服务的配置
	HttpServerCfg        _httpserver.Config // HTTP服务器的配置
	HttpServiceCfg       _http.Config       // HTTP请求处理器的配置
	HttpHandlerCfg       httphandler.Config // HTTP请求处理器的配置
	HttpLoggerCfg        _httplog.Config    // HTTP流量日志服务的配置
	WorkerPoolServiceCfg _wpservice.Config  // 工作池处理器服务的配置
	MetricsCfg           _metrics.Config    // 度量收集的配置
}

// ValidateConfig validate config
func (cfg *Config) ValidateConfig() error {

	if !(cfg.LoggerCfg.GlobalLevel == _log.LEVEL_DEBUG || cfg.LoggerCfg.GlobalLevel == _log.LEVEL_ERROR || cfg.LoggerCfg.GlobalLevel == _log.LEVEL_INFO) {
		return _err.NewTyped(_err.ERR_INCORRECT_LOG_LEVEL, _err.ERR_UNDEFINED_ID, cfg.LoggerCfg.GlobalLevel).PrintfError()
	}

	// 是否在命令行中指定了JSON web token密钥
	if cfg.HttpServiceCfg.UseJWT && cfg.ArgsJwtKey == "" {
		return _err.NewTyped(_err.ERR_EMPTY_JWT_KEY, _err.ERR_UNDEFINED_ID).PrintfError()
	}

	// 是否在命令行中指定了JSON Web Token（JWT）密钥
	if cfg.HttpServiceCfg.AuthType == _http.AUTH_TYPE_INTERNAL && (cfg.ArgsHTTPUser == "" || cfg.ArgsHTTPPass == "") {
		return _err.NewTyped(_err.ERR_EMPTY_HTTP_USER, _err.ERR_UNDEFINED_ID).PrintfError()
	}

	if !(cfg.HttpServiceCfg.AuthType == _http.AUTH_TYPE_NONE || cfg.HttpServiceCfg.AuthType == _http.AUTH_TYPE_MSAD || cfg.HttpServiceCfg.AuthType == _http.AUTH_TYPE_INTERNAL) {
		return _err.NewTyped(_err.ERR_INCORRECT_AUTH_TYPE, _err.ERR_UNDEFINED_ID, cfg.HttpServiceCfg.AuthType).PrintfError()
	}

	return nil
}

func replaceCfgArgsEnv(cfgParamName string, cfgParam *string, argsParamName string, argsParam string, envParamName string, envParam string) {
	if argsParam != "" {
		_log.Info("YAML config parameter '" + cfgParamName + "'='" + *cfgParam + "' was replaced with parameter '" + argsParamName + "'='" + argsParam + "' from command string")
		*cfgParam = argsParam
	} else if argsParam == "" && envParam != "" {
		_log.Info("YAML config parameter '" + cfgParamName + "'='" + *cfgParam + "' was replaced with environment '" + envParamName + "'='" + envParam + "'")
		*cfgParam = envParam
	}
}

// LoadYamlConfig load configuration file
func (cfg *Config) LoadYamlConfig(fileName string) error {
	if cfg != nil {
		var err error
		var fileInfo os.FileInfo
		var file *os.File

		cfg.ConfigFile = fileName

		if fileName == "" {
			return _err.NewTyped(_err.ERR_EMPTY_CONFIG_FILE, _err.ERR_UNDEFINED_ID).PrintfError()
		}
		_log.Info("Loading config from file: FileName", fileName)

		// 读取文件信息
		fileInfo, err = os.Stat(fileName)
		if os.IsNotExist(err) {
			return _err.NewTyped(_err.ERR_CONFIG_FILE_NOT_EXISTS, _err.ERR_UNDEFINED_ID, fileName).PrintfError()
		}

		_log.Info("Config file exist: FileName, FileInfo", fileName, fileInfo)

		{ // 从文件中读取配置
			file, err = os.Open(fileName)
			if err != nil {
				return err
			}
			defer func() {
				if file != nil {
					err = file.Close()
					if err != nil {
						_ = _err.WithCauseTyped(_err.ERR_COMMON_ERROR, _err.ERR_UNDEFINED_ID, err, "config.LoadYamlConfig -> os.File.Close()").PrintfError()
					}
				}
			}()

			decoder := yaml.NewDecoder(file)
			err = decoder.Decode(cfg)

			if err != nil {
				return _err.WithCauseTyped(_err.ERR_CONFIG_FILE_LOAD_ERROR, _err.ERR_UNDEFINED_ID, err, fileName).PrintfError()
			}
		} // 从文件读取配置

		{ // 替换环境和命令行中的参数，命令行优先
			replaceCfgArgsEnv(
				"http_server.listen_spec", &cfg.HttpServerCfg.ListenSpec,
				"listenspec", cfg.ArgsHTTPListenSpec,
				ENV_APP_HTTP_LISTEN_SPEC, cfg.EnvHTTPListenSpec)

			replaceCfgArgsEnv(
				"http_service.http_user", &cfg.HttpServiceCfg.HTTPUser,
				"httpuser", cfg.ArgsHTTPUser,
				ENV_APP_HTTP_USER, cfg.EnvHTTPUser)

			replaceCfgArgsEnv(
				"http_service.http_pass", &cfg.HttpServiceCfg.HTTPPass,
				"httppass", cfg.ArgsHTTPPass,
				ENV_APP_HTTP_PASS, cfg.EnvHTTPPass)

			replaceCfgArgsEnv(
				"http_service.jwt_key", &cfg.HttpServiceCfg.JwtKeyStr,
				"jwt_key", cfg.ArgsJwtKey,
				ENV_APP_JWT_KEY, cfg.EnvJwtKey)
			cfg.HttpServiceCfg.JwtKey = []byte(cfg.HttpServiceCfg.JwtKeyStr)

			replaceCfgArgsEnv(
				"logger.global_level", &cfg.LoggerCfg.GlobalLevel,
				"loglevel", cfg.ArgsLogLevel,
				ENV_APP_LOG_LEVEL, cfg.EnvLogLevel)

			replaceCfgArgsEnv(
				"logger.log_file", &cfg.LoggerCfg.GlobalFilename,
				"logfile", cfg.ArgsLogFile,
				ENV_APP_LOG_FILE, cfg.EnvLogFile)

		} // 用环境和命令行中的参数替换，命令行参数优先

		return cfg.ValidateConfig()
	}
	return _err.NewTyped(_err.ERR_INCORRECT_CALL_ERROR, _err.ERR_UNDEFINED_ID, "if cfg != nil {}").PrintfError()
}
